// TODO
// - work on IE compatibility?

// var imgRoot = ''; // for original functionality
var imgRoot = 'http://www.math.brown.edu/~casey/viewer-images/';

var XMLHttpFactories = [
	function () {return new XMLHttpRequest()},
	function () {return new ActiveXObject("Msxml2.XMLHTTP")},
	function () {return new ActiveXObject("Msxml3.XMLHTTP")},
	function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];

var imageFileType = '.png';
var imageWidth = '800px';
var imageHeight = '600px';
var bifWidth = '400px';
var bifHeight = '400px';

var currSlot = 0;

var imageTypes =
{
  height2d: {suffix: "height_2D", label: "Height 2D"},
  height3d: {suffix: "height_3D", label: "Height 3D"},
  pressure2d: {suffix: "pressure_2D", label: "Pressure 2D"},
  pressure3d: {suffix: "pressure_3D", label: "Pressure 3D"},
  streamlines: {suffix: "streamlines", label: "Streamlines"},
};

function contains(array, obj)
{
	var i = array.length;
	while (i--)
	{
		if (array[i] === obj)
		{
			return true;
		}
	}
	return false;
}


function waveVorticityStrength(wave, vorticityClass)
{
	var strength = null;
	
	if(vorticityClass === 'exp')
		{
			strength = wave.attr('A');
		}
		else if(vorticityClass === 'tanh')
		{
			strength = 'A' + wave.attr('A') + '.B' + wave.attr('B');
		}
		else if(vorticityClass === 'step')
		{
			var splitPath = wave.attr('path').split('/');
			strength = splitPath[1] + '/' + splitPath[2];
		}
		
	return strength;
}

function grabVorticityStrengths(responseXML, vorticityClass)
{
	var vorticityStrengths = [];
	$(responseXML).find('wave').each(function ()
	{
		var wave = $(this);
		var strength = waveVorticityStrength(wave, vorticityClass);
		if(!contains(vorticityStrengths, strength))
		{
			vorticityStrengths.push(strength);
		}
	});
	
	if(vorticityClass == 'exp')
	{
		vorticityStrengths.sort(function(x,y){ return x-y; });
	}

	return vorticityStrengths;
}

function extractBifData(responseXML, vorticityClass, vorticityStrength)
{
	var bifData = [];
	
	$(responseXML).find('wave').each(function ()
	{
		var wave = $(this);
		var strength = waveVorticityStrength(wave, vorticityClass);
		
		if (strength == vorticityStrength)
		{
			bifData.push([parseFloat(wave.attr('Q')), parseFloat(wave.attr('amplitude'))]);
		}
	});
	return bifData;
}

function locateStagnatingWave(responseXML, vorticityClass, vorticityStrength)
{
	var stagnatingWave = null;
	$(responseXML).find('wave').each(function ()
	{
		if (waveVorticityStrength($(this), vorticityClass) == vorticityStrength)
		{
			if (!stagnatingWave || (stagnatingWave.attr('time') < $(this).attr('time')))
			{
				stagnatingWave = $(this);
			}
		}
	});
	
	return stagnatingWave;
}

function createXMLHTTPObject() {
	var xmlhttp = false;
	for (var i=0;i<XMLHttpFactories.length;i++) {
		try {
			xmlhttp = XMLHttpFactories[i]();
		}
		catch (e) {
			continue;
		}
		break;
	}
	return xmlhttp;
}

function fetchXML(selectedClass, callback)
{
	var xhr = createXMLHTTPObject();
	if(!xhr)
	{
		return;
	}
	
	var filename = 'db/db_' + selectedClass + '.xml';
	
	xhr.open('GET', filename, true);
	//xhr.setRequestHeader('User-Agent','XMLHTTP/1.0');
	
	xhr.onreadystatechange = function ()
	{
		if (xhr.readyState != 4)
		{
			return;
		}
		if (xhr.status != 200 && xhr.status != 304)
		{
			alert('HTTP error ' + xhr.status);
			return;
		}
		
		// Non-general functionality here					
		callback(xhr.responseXML, selectedClass);
	};
	
	xhr.send(null);
	
	return xhr;
}

function showTooltip(x, y, contents)
{
	$('<div id="tooltip">' + contents + '<\/div>').css( {
		position: 'absolute',
		display: 'none',
		top: y + 10,
		left: x + 10,
		border: '1px solid #fdd',
		padding: '2px',
		'background-color': '#fee',
		opacity: 0.80
	}).appendTo("body").fadeIn(200);
}

function showWaveInfo(wave)
{
  if(wave.attr('Q') != undefined)
  {
    var table = $('#waveInfo'+currSlot);
    table.empty();
    var waveTime = new Date(wave.attr('time') * 1000);
    var fields = 
    {
      path: wave.attr('path'),
      Q: wave.attr('Q'),
      p0: wave.attr('p0'),
      amplitude: wave.attr('amplitude'),
      time: waveTime.toLocaleString(),
    };
    for (f in fields) {
      table.append("<tr><td>"+f+':</td><td>'+fields[f]+'</td></tr>');
    }
  }
  else
  {
    $('#waveInfo').text('could not retrieve wave from database, reload the page and try again (sorry)');
  }
  
  $('#waveInfo').show();
}

function hideWaveInfo()
{
	$('#waveInfo').hide();
	$('#tooltip').hide();
}

function loadImages(imagePrefix) {
  var theImg;

  for ( var type in imageTypes )
  {
    theImg = new Image();
    theImg.src = imagePrefix + '_' + imageTypes[type].suffix + imageFileType;

    placeholder = $('#'+type+'Placeholder'+currSlot);
    placeholder.empty()
    placeholder.append(theImg);
    placeholder.show();
  }

  $('#tabs').show();
}

function showWave(w)
{

  showWaveInfo(w);

  var imagePrefix = imgRoot + w.attr('path').replace('files','pressure');
  loadImages(imagePrefix);
}

function setupClass(responseXML, selectedClass)
{
	// insert the dropdown of vorticity strengths
	var vorticityStrengths = grabVorticityStrengths(responseXML, selectedClass);
	
	var vorticityStrengthMenu = document.createElement('select');
	vorticityStrengthMenu.id = 'vorticity';
	vorticityStrengthMenu.name = 'vorticity';
	$('#spanVorticityStrengthSelect').empty();
	$('#spanVorticityStrengthSelect').append(vorticityStrengthMenu);
	
	var optgroup = document.createElement('optgroup');
	optgroup.label = 'Vorticity';
	vorticityStrengthMenu.appendChild(optgroup);
	
	var dummy = document.createElement('option');
	dummy.value = '';
	dummy.text = '';
	optgroup.appendChild(dummy);

	for (var i in vorticityStrengths)
	{
		var option = document.createElement('option');
		option.value = vorticityStrengths[i];
		option.text = vorticityStrengths[i];
		optgroup.appendChild(option);
	}
	
	$('#spanVorticityStrengthText').text('and a vorticity strength:');
	$('#spanVorticityStrengthText').show();
	$('#spanVorticityStrengthSelect').show();
	
	$('#vorticity').change(function(){vorticityChangeCallback(this,responseXML,selectedClass);});
}

function makeBifPlot(responseXML, selectedClass, selectedStrength)
{
	var bifData;
	var bifOptions =
	{
		// set plotting options here
		lines: {show: false},
		points: {show: true},
		grid: {hoverable: true, clickable: true, backgroundColor: '#FFFFFF', borderWidth: '1'},
		xaxis: {autoscaleMargin: '0.01'}
	};
	$('#bifPlaceholder').css('width',bifWidth);
	$('#bifPlaceholder').css('height',bifHeight);
	bifData = extractBifData(responseXML, selectedClass, selectedStrength);
	$('#bifPlaceholder').show();
	var plot = $.plot($('#bifPlaceholder'), [ { data: bifData, color: '#FF0000'} ], bifOptions);

	// resizing doesn't quite work yet
//			$("#bifPlaceholder").resizable({
//			  stop: function(event,ui) {
//			    $.plot($('#bifPlaceholder'), [ { data: bifData, color: '#FF0000'} ], bifOptions);
//			  }
//			});
	
	$('#buttons').show();
	
	// find the stagnating wave and display accordingly
	$('#stagnatingWaveButton').click(function ()
	{
	  showWave(locateStagnatingWave(responseXML, selectedClass, selectedStrength));
	});

	var previousPoint = null;
	
	// for the tooltip
	$('#bifPlaceholder').bind('plothover', function (event, pos, item)
	{
		if (item)
		{
			if (previousPoint != item.datapoint)
			{
				previousPoint = item.datapoint;
				
				$('#tooltip').remove();
				var q = item.datapoint[0].toFixed(6);
				var amp = item.datapoint[1].toFixed(6);
				showTooltip(item.pageX, item.pageY, '(' + q + ', ' + amp + ')');
			}
		}
		else
		{
			$('#tooltip').remove();
			previousPoint = null;
		}
	});
	
	// for the point click
	$('#bifPlaceholder').bind('plotclick', function (event, pos, item)
	{
	  if (item)
	  {	
	    // clicked near (enough) to a point, so grab & show the wave
	    var x = item.datapoint[0];
	    var y = item.datapoint[1];
	    var clickedWave = $(responseXML).find("wave[Q='" + x + "']");

	    showWave(clickedWave);
	  }
		
	});
}

function vorticityChangeCallback(widget, responseXML, selectedClass)
{
	
	var selectedStrength = (widget.options[widget.selectedIndex]).value;
	
	
	if (selectedStrength === '')
	{
                $('#tabs').hide();
		$('#bifPlaceholder').hide();
		$('#buttons').hide();
	}
	else
	{	
	  makeBifPlot(responseXML, selectedClass, selectedStrength);
	}
}

function classChangeCallback() {
  // Do some cleanup
  $('#tabs').hide();
  $('#bifPlaceholder').hide();
  $('#buttons').hide();

  var selection = this.options[this.selectedIndex];
  var selectedClass = selection.value;

  $('#spanVorticityStrengthSelect').hide();

  if (selectedClass != '')
  {
      $('#spanVorticityStrengthText').text('loading...');
      $('#spanVorticityStrengthText').show();
      fetchXML(selectedClass, setupClass);
  }
  else
  {
      $('#spanVorticityStrengthText').hide();
  }
}

function createTabs() {
  for ( var type in imageTypes )
  {
    $('#tabs > ul').append('<li><a href="#' + type + 'Tab"><span>'+imageTypes[type].label+'</span></a></li>');
    $('#tabs').append('<div id="' + type + 'Tab" />')
  }
  $('#tabs').tabs();
  $('#tabs').hide();
}

function createPlaceholders() {
  for ( var type in imageTypes )
  {
    var i;
    for (i=0; i<2; i++)
    {
      var placeholder = document.createElement('div');
      placeholder.id = type + 'Placeholder'+i;
      $(placeholder).css('height',imageHeight);
      $(placeholder).css('width',imageWidth);
      //$(placeholder).css('border','1px solid black');
      $('#'+type+'Tab').append(placeholder);
      $(placeholder).hide();
    }
  }
}

function createInfoTables() {
  var i;
  for (i=0; i<2; i++)
  {
    var table = document.createElement('table');
    table.id = "waveInfo"+i;
    table.border = 1;
    $('#waveInfo').append("Slot "+i);
    $('#waveInfo').append(table);
  }
}

function viewer_initialize()
{	
  hideWaveInfo();
  $('#buttons').hide();
  
  $('#vorticityClass').change(classChangeCallback);
  $('#slotSelect').change(function(){
    currSlot = this.options[this.selectedIndex].value;
  });

  createInfoTables();
  createTabs();
  createPlaceholders();
}

